﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GrainManage.Entities.Account;
using GrainManage.Server.Factory;
using GrainManage.Entities;
using GrainManage.Server.Resources;
using GrainManage.Data.Model.Table;
using System.Text.RegularExpressions;
using GrainManage.Encrypt;
using GrainManage.Entities.Encrypt;

namespace GrainManage.Server.Business
{
    class AccountBusiness : BaseBusiness, GrainManage.Interface.IAccount
    {
        //************************************************POST************************************************

        public OutputRegister Register(InputRegister input)
        {
            var result = new OutputRegister();
            try
            {
                var service = ObjectFactory.AccountService;
                if (input.Account == null || string.IsNullOrEmpty(input.Account.UserName))
                {
                    SetResponse(StatusCode.NameEmpty, result);
                }
                else if (string.IsNullOrEmpty(input.Account.Password))
                {
                    SetResponse(StatusCode.PwdEmpty, result);
                }
                else if (service.GetAccountView(input.Account.UserName) != null)
                {
                    SetResponse(StatusCode.NameExist, result);
                }
                else
                {
                    if (string.IsNullOrEmpty(input.Account.Email) || IsEmailMatch(input.Account.Email))
                    {
                        input.Account.Password = Decrypt(input.Account.Password, input.EncryptModel, string.Empty);
                        if (string.IsNullOrEmpty(input.Account.Password))
                        {
                            SetResponse(StatusCode.InvalidDecryptModel, result);
                        }
                        else
                        {
                            var affected = service.Register(input.Account);
                            if (affected != 0)
                            {
                                SetResponse(StatusCode.Success, result);
                            }
                        }
                    }
                    else
                    {
                        SetResponse(StatusCode.EmailFormatNotMatch, result);
                    }
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputManageAccount ManageAccount(InputManageAccount input)
        {
            var result = new OutputManageAccount();
            try
            {
                var authentication = input.Authentication;
                if (authentication != null && !string.IsNullOrWhiteSpace(authentication.UserName) && !string.IsNullOrWhiteSpace(authentication.Guid))
                {
                    var service = ObjectFactory.AccountService;
                    var affected = service.ManageAccount(input.Account);
                    if (affected > 0)
                    {
                        SetResponse(StatusCode.Success, result);
                    }
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputSignIn SignIn(InputSignIn input)
        {
            var result = new OutputSignIn();
            try
            {
                if (!string.IsNullOrWhiteSpace(input.UserName))
                {
                    var service = ObjectFactory.AccountService;
                    var account = service.GetAccountView(input.UserName);
                    if (account != null)
                    {
                        if (account.IsApproved)
                        {
                            input.Password = Decrypt(input.Password, input.EncryptModel, account.EncryptKey);
                            if (string.IsNullOrEmpty(input.Password))
                            {
                                SetResponse(StatusCode.InvalidDecryptModel, result);
                            }
                            else
                            {
                                var isValidated = service.Validate(input.UserName, input.Password);
                                if (!isValidated)
                                {
                                    SetResponse(StatusCode.PwdNotMatch, result);
                                }
                                else
                                {
                                    service.ChangeOnLineState(input.UserName, true);
                                    service.LogLogin(input.UserName, GrainManage.Server.Tool.IPUtil.RequestHostAddress);
                                    result.Guid = account.Guid;
                                    SetResponse(StatusCode.Success, result);
                                }
                            }
                        }
                        else
                        {
                            SetResponse(StatusCode.UserNotActivated, result);
                        }
                    }
                    else
                    {
                        SetResponse(StatusCode.NameNotExist, result);
                    }
                }
                else
                {
                    SetResponse(StatusCode.NameEmpty, result);
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputResetPassword ResetPassword(InputResetPassword input)
        {
            var result = new OutputResetPassword();
            try
            {
                if (string.IsNullOrWhiteSpace(input.UserName))
                {
                    SetResponse(StatusCode.NameEmpty, result);
                }
                else if (string.IsNullOrEmpty(input.Email))
                {
                    SetResponse(StatusCode.EmailEmpty, result);
                }
                else if (!IsEmailMatch(input.Email))
                {
                    SetResponse(StatusCode.EmailFormatNotMatch, result);
                }
                else
                {
                    var service = ObjectFactory.AccountService;
                    var account = service.GetAccountView(input.UserName);
                    if (account != null)
                    {
                        if (account.IsApproved)
                        {
                            var pwd = service.ResetPassword(input.UserName, input.Email);
                            if (string.IsNullOrEmpty(pwd))
                            {
                                SetResponse(StatusCode.EmailNotMatch, result);
                            }
                            else
                            {
                                //var title=TextResource.ResetPasswordTitle;
                                //var body = TextResource.ResetPasswordContent.Replace("#UserName#", input.UserName).Replace("#Password#", pwd);
                                var patternService = ObjectFactory.PatternService;
                                var title = patternService.GetContent("ResetPasswordTitle");
                                var body = patternService.GetContent("ResetPasswordContent").Replace("#UserName#", input.UserName).Replace("#Password#", pwd);
                                if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(body))
                                {
                                    SetResponse(StatusCode.NoPatternData, result);
                                }
                                else
                                {
                                    var password = DESEncrypt.Decrypt(ObjectFactory.GetAppConfig("Password"));
                                    var smtp = new GrainManage.Server.Util.EmailUtil(ObjectFactory.GetAppConfig("From"), password);
                                    smtp.SendAsync(input.Email, body, title);
                                    SetResponse(StatusCode.Success, result);
                                }
                            }
                        }
                        else
                        {
                            SetResponse(StatusCode.UserNotActivated, result);
                        }
                    }
                    else
                    {
                        SetResponse(StatusCode.NameNotExist, result);
                    }
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputChangePassword ChangePassword(InputChangePassword input)
        {
            var result = new OutputChangePassword();
            try
            {
                if (string.IsNullOrWhiteSpace(input.Authentication.UserName))
                {
                    SetResponse(StatusCode.NameEmpty, result);
                }
                else if (string.IsNullOrEmpty(input.OldPassword) || string.IsNullOrEmpty(input.NewPassword))
                {
                    SetResponse(StatusCode.PwdEmpty, result);
                }
                else
                {
                    var service = ObjectFactory.AccountService;
                    var account = service.GetAccountView(input.Authentication.UserName);
                    if (account.IsApproved)
                    {
                        input.OldPassword = Decrypt(input.OldPassword, input.EncryptModel, account.EncryptKey);
                        input.NewPassword = Decrypt(input.NewPassword, input.EncryptModel, account.EncryptKey);
                        if (string.IsNullOrEmpty(input.OldPassword) || string.IsNullOrEmpty(input.NewPassword))
                        {
                            SetResponse(StatusCode.InvalidDecryptModel, result);
                        }
                        else
                        {
                            var affected = service.ChangePassword(input.Authentication.UserName, input.OldPassword, input.NewPassword);
                            if (affected == 0)
                            {
                                SetResponse(StatusCode.PwdNotMatch, result);
                            }
                            else
                            {
                                SetResponse(StatusCode.Success, result);
                            }
                        }
                    }
                    else
                    {
                        SetResponse(StatusCode.UserNotActivated, result);
                    }
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputSignOut SignOut(InputSignOut input)
        {
            var result = new OutputSignOut();
            try
            {
                var authentication = input.Authentication;
                var service = ObjectFactory.AccountService;
                service.ChangeOnLineState(authentication.UserName, false);
                service.ResetGuid(authentication.UserName);
                SetResponse(StatusCode.Success, result);
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        public OutputGetEncryptKey GetEncryptKey(InputGetEncryptKey input)
        {
            var result = new OutputGetEncryptKey();
            try
            {
                var service = ObjectFactory.AccountService;
                var account = service.GetAccountView(input.AccountName);
                if (account != null)
                {
                    EncryptModel model = ConvertToEncryptModel(input.EncryptModel);
                    if (model == EncryptModel.DES)
                    {
                        result.EncryptKey = service.ResetEncryptKey(input.AccountName);
                        if (string.IsNullOrEmpty(result.EncryptKey))
                        {
                            result.EncryptKey = account.EncryptKey;
                            SetResponse(StatusCode.ResetCountLimit, result);
                        }
                        else
                        {
                            SetResponse(StatusCode.Success, result);
                        }
                    }
                    else if (model == EncryptModel.RSA)
                    {
                        result.EncryptKey = TextResource.PublicKey;
                        SetResponse(StatusCode.Success, result);
                    }
                    else
                    {
                        SetResponse(StatusCode.InvalidDecryptModel, result);
                    }
                }
                else
                {
                    SetResponse(StatusCode.NameNotExist, result);
                }
            }
            catch (Exception e)
            {
                SetResponse(StatusCode.Failed, result, e.Message);
                WriteLog(System.Reflection.MethodBase.GetCurrentMethod(), e, input, result);
            }

            return result;
        }

        //辅助方法

        private string Decrypt(string textToDecrypt, int encryptModel, string decryptKey)
        {
            string decryptedText = string.Empty;
            EncryptModel encryptMethod = ConvertToEncryptModel(encryptModel);
            switch (encryptMethod)
            {
                case EncryptModel.Original:
                    decryptedText = textToDecrypt;
                    break;
                case EncryptModel.DES:
                    decryptedText = string.IsNullOrEmpty(decryptKey) ? DESEncrypt.Decrypt(textToDecrypt) : DESEncrypt.Decrypt(textToDecrypt, decryptKey);
                    break;
                case EncryptModel.RSA:
                    decryptedText = RSAEncrypt.Decrypt(textToDecrypt, TextResource.PrivateKey);
                    break;
            }
            return decryptedText;
        }

        private EncryptModel ConvertToEncryptModel(int encryptModel)
        {
            switch (encryptModel)
            {
                case 0:
                    return EncryptModel.Original;
                case 1:
                    return EncryptModel.DES;
                case 2:
                    return EncryptModel.RSA;
                case 3:
                    return EncryptModel.MD5;
                default:
                    return EncryptModel.Invalid;
            }
        }

        private bool IsEmailMatch(string email)
        {
            return Regex.IsMatch(email, @"^[a-zA-Z0-9_+.-]+\@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,4}");
        }

    }
}
